package com.proton.carepatchtemp.activity;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.view.WindowManager;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.apkfuns.logutils.LogUtils;
import com.proton.carepatchtemp.R;
import com.proton.carepatchtemp.application.VCare;
import com.proton.carepatchtemp.base.BaseActivity;
import com.proton.carepatchtemp.constant.Codes;
import com.proton.carepatchtemp.constant.Extras;
import com.proton.carepatchtemp.constant.UUIDs;
import com.proton.carepatchtemp.database.Bean.BleWriteData;
import com.proton.carepatchtemp.database.table.Device;
import com.proton.carepatchtemp.utils.FileUtils;
import com.proton.carepatchtemp.utils.TastyUtils;
import com.proton.carepatchtemp.utils.ThreadUtils;
import com.proton.carepatchtemp.utils.ble.BlueUtils;
import com.proton.carepatchtemp.utils.eventbus.MainEvent;
import com.proton.carepatchtemp.utils.net.DeviceCenter;
import com.sdsmdg.tastytoast.TastyToast;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.Queue;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;

public class FireWareUpdateActivity extends BaseActivity {

    private static final Queue<BleWriteData> mWriteQueue = new ConcurrentLinkedQueue<>();//数据队列
    private static boolean isWriting = false;//正在写入数据
    BluetoothGatt mGatt = null;
    Device mDevice;
    //    private BufferedInputStream mBufin;
    int buffSize = 16;
    boolean isfinish = false;
    boolean isNTFWrite = false;
    boolean isNTFCallBack = false;
    boolean isFinishUpdate = false;
    DecimalFormat df = new java.text.DecimalFormat("#0.00");
    private ProgressBar mPbFwUpdate;
    private TextView mTvUpdateProgress;
    private BluetoothAdapter mBlueToothAdapter;
    private BluetoothDevice mBluetoothDevice;
    private BluetoothGattService resetGattServer;
    private BluetoothGattCharacteristic resetChar;
    //设备是否重置
    private boolean isReset = false;
    private Handler mHandler = new Handler();
    private BluetoothGattService updateService;
    private BluetoothGattCharacteristic writeChar;
    private BluetoothGattCharacteristic callBackNtf;
    private BluetoothGattCharacteristic finish;
    private String updateMac = "0A:D0:AD:0A:D0:AD";
    private File mFile;
    private FileInputStream mInputStream;
    private int index = 1;
    private int length = 0;
    private BleWriteData latSendData;
    private BleWriteData reSendData;//重新发送的数据
    private TimeOutThread timeOutThread;
    private boolean timeOutThread_Start = false;//超时线程是否开始
    private int timeOutNum = 0;//超时次数
    private int timeOutTime = 0; //超时时间标记
    private byte[] mBytes;

    @Override
    public void dealEvent(MainEvent event) {
        if (event.getId() == Codes.DEVICE_UPDATE_SUCCEED) {

        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //屏幕常亮
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.activity_fire_ware_update);
        initView();
        setListener();
        if (getIntent().getExtras() == null) {
            finish();
        } else {
            mDevice = (Device) getIntent().getExtras().getSerializable(Extras.DEVICE_DETIAL);
        }

        mFile = new File(FileUtils.firmWare + File.separator + VCare.get().getFirmWare().getVersion());
        if (mFile.exists()) {
            try {
                mInputStream = new FileInputStream(mFile);
                mBytes = (getBytes(mInputStream));
                length = mBytes.length / buffSize;
                LogUtils.d("文件大小为 + " + FileUtils.getFormatSize(FileUtils.getFolderSize(mFile)));

            } catch (FileNotFoundException e) {
                LogUtils.d(e);
                TastyUtils.makeText(R.string.string_update_fail, TastyToast.LENGTH_LONG, TastyToast.ERROR);
                finish();
            } finally {
                try {
                    mInputStream.close();
                } catch (IOException e) {
                    LogUtils.e(e);
                }
            }
        }

        if (getIntent().getExtras().containsKey(Extras.DEVICE_UPDATE_KEY)) {
            ThreadUtils.runOnOtherThread(() -> {
                mBlueToothAdapter = BlueUtils.get().getBlueToothAdapter();
                if (mBlueToothAdapter.getState() == BluetoothAdapter.STATE_OFF) {
                    mBlueToothAdapter.enable();
                }
                firmWareUpdate();
            });

            return;
        }

        ThreadUtils.runOnOtherThread(() -> {
            mBlueToothAdapter = BlueUtils.get().getBlueToothAdapter();
            if (mBlueToothAdapter.getState() == BluetoothAdapter.STATE_OFF) {
                mBlueToothAdapter.enable();
            }
            mBluetoothDevice = mBlueToothAdapter.getRemoteDevice(mDevice.getBtaddress());
            if (mBluetoothDevice == null) {
                mHandler.post(() -> {
                    TastyUtils.makeTextShort(R.string.string_update_fail, TastyToast.CONFUSING);
                    finish();
                });
                return;
            }
            try {
                mGatt = mBluetoothDevice.connectGatt(FireWareUpdateActivity.this, false, new BluetoothGattCallback() {
                    @Override
                    public void onConnectionStateChange(BluetoothGatt mGatt, int status, int newState) {
                        if (BluetoothProfile.STATE_CONNECTED == newState) {
                            mGatt.discoverServices();
                        }

                        if (BluetoothProfile.STATE_DISCONNECTED == newState) {
                            if (isReset) {
                                mGatt.close();
                            } else {

                                mHandler.postDelayed(() -> {
                                    if (index != 0) {
                                        return;
                                    }
                                    TastyUtils.makeText(R.string.string_update_fail, TastyToast.LENGTH_LONG, TastyToast.ERROR);
                                    finish();
                                }, 10 * 1000);
                            }
                        }
                        super.onConnectionStateChange(mGatt, status, newState);
                    }

                    @Override
                    public void onServicesDiscovered(BluetoothGatt mGatt, int status) {
                        if (BluetoothGatt.GATT_SUCCESS == status) {
                            resetGattServer = mGatt.getService(UUID.fromString(UUIDs.SERVER_RESET_DEVICE));
                            if (null == resetGattServer) {
                                LogUtils.d("重置服务没有发现！resetGattServer");
                                mGatt.close();
                                mHandler.post(() -> {
                                    TastyUtils.makeText(R.string.string_update_fail, TastyToast.LENGTH_LONG, TastyToast.ERROR);
                                    finish();
                                });
                            }
                            LogUtils.d("resetGattServer");
                            resetChar = resetGattServer.getCharacteristic(UUID.fromString(UUIDs.CHARACTER_RESET_DEVICE));
                            if (null == resetChar) {
                                LogUtils.d("重置服务没有发现！resetChar");
                                mHandler.post(() -> {
                                    TastyUtils.makeText(R.string.string_update_fail, TastyToast.LENGTH_LONG, TastyToast.ERROR);
                                    finish();
                                });
                            }
                            LogUtils.d("resetChar");
                            resetChar.setValue("1");
                            resetChar.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);

                            while (!mGatt.writeCharacteristic(resetChar)) {
//                                if (!) {
                                isReset = true;
                                LogUtils.e("Reset Device Failed !");
//                                }
                            }

//                            mGatt.close();

                        } else {
                            mGatt.close();
                        }
                        super.onServicesDiscovered(mGatt, status);
                    }

                    @Override
                    public void onCharacteristicChanged(BluetoothGatt mGatt, BluetoothGattCharacteristic characteristic) {
                        super.onCharacteristicChanged(mGatt, characteristic);
                    }

                    @Override
                    public void onCharacteristicWrite(BluetoothGatt mGatt, BluetoothGattCharacteristic characteristic, int status) {
                        if (BluetoothGatt.GATT_SUCCESS == status) {
                            switch (characteristic.getUuid().toString().trim()) {
                                case UUIDs.CHARACTER_RESET_DEVICE:
                                    LogUtils.d("Reset Device Succeed!");
                                    isReset = true;
//                                    mGatt.close();
//                                    firmWareUpdate();
                                    break;
                            }
                        }
                        super.onCharacteristicWrite(mGatt, characteristic, status);
                    }

                });
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                Thread.sleep(10 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            mGatt.close();
            firmWareUpdate();
        });
//        connectDevice();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (null != mGatt) {
            mGatt.close();
        }
        mHandler.removeCallbacksAndMessages(null);
    }

    @Override
    protected void setListener() {

    }

    private byte[] getBytes(FileInputStream inputStream) {
        //获取文件大小字节
        int length = 0;
        try {
            length = inputStream.available();
        } catch (IOException e) {
            e.printStackTrace();
        }

        //读取文件字节到一个数组中
        int bytesRead = 0;
        int bytesToRead = length;
        byte[] input = new byte[bytesToRead];
        while (bytesRead < bytesToRead) {
            int result = 0;
            try {
                result = inputStream.read(input, bytesRead, bytesToRead - bytesRead);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (result == -1)
                break;
            bytesRead += result;
        }
        return input;
    }

    @Override
    public void onEventMainThread(MainEvent event) {
        dealEvent(event);
    }


    /**
     * 连接设备 如果GATT列表中对应的GATT对象不为空，则为重连
     */
    private void firmWareUpdate() {
        mBluetoothDevice = mBlueToothAdapter.getRemoteDevice(updateMac);
        mBluetoothDevice.connectGatt(FireWareUpdateActivity.this, false, new BluetoothGattCallback() {
            @Override
            public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                if (newState == BluetoothProfile.STATE_CONNECTED) {
                    mGatt = gatt;
                    gatt.discoverServices();
                    LogUtils.d("升级连接成功！");
                }

                if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                    mGatt.close();
                    mWriteQueue.clear();
                    if (index != length - 1) {
                        index = 0;
//                        firmWareUpdate();
                    } else {
                        mHandler.post(() -> {
                            gatt.close();
                            TastyUtils.makeText(R.string.string_update_success, TastyToast.LENGTH_LONG, TastyToast.SUCCESS);
                            VCare.get().needUpdate -= 1;

                            if (null != mDevice)
                                DeviceCenter.updateByBtaddress(mDevice.getBtaddress(), VCare.get().getFirmWare().getVersion());

                            finish();
                        });
                    }
                    LogUtils.d("升级连接断开！");
                }
                super.onConnectionStateChange(gatt, status, newState);
            }

            @Override
            public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    LogUtils.d("连接成功");
                    updateService = gatt.getService(UUID.fromString(UUIDs.SERVER_UPDATE_FIRMWARE));
                    if (null != updateService) {
                        writeChar = updateService.getCharacteristic(UUID.fromString(UUIDs.CHARACTER_WRITE_FIRMWARE));
                        callBackNtf = updateService.getCharacteristic(UUID.fromString(UUIDs.CHARACTER_CALLBACK_WRITE));
                        finish = updateService.getCharacteristic(UUID.fromString(UUIDs.CHARACTER_FINISH_UPDATE));
                    }

                    if (null == writeChar || null == callBackNtf || null == finish) {
                        gatt.close();
                        mHandler.post(() -> {
                            TastyUtils.makeText(R.string.string_update_fail, TastyToast.LENGTH_LONG, TastyToast.ERROR);
                            finish();
                        });
                    }

                    enableNotification(true, gatt, writeChar);
                    enableNotification(true, gatt, callBackNtf);
                    enableNotification(true, gatt, finish);
                    nextWrite();

                } else {
                    LogUtils.d("连接失败");
                    mHandler.post(() -> {
                        TastyUtils.makeText(R.string.string_update_fail, TastyToast.LENGTH_LONG, TastyToast.ERROR);
                        gatt.close();
//                        mWriteQueue.clear();
                        finish();
//                        ThreadUtils.runOnOtherThread(() -> {
//                            index = 0;
//                            firmWareUpdate();
//                        });
                    });
                }
                super.onServicesDiscovered(gatt, status);
            }

            @Override
            public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
                switch (characteristic.getUuid().toString().trim()) {
                    case UUIDs.CHARACTER_WRITE_FIRMWARE:
                        LogUtils.d(BlueUtils.bytesToHexString(characteristic.getValue()));
                        mHandler.post(() -> {
                            TastyUtils.makeText(R.string.string_update_fail, TastyToast.LENGTH_LONG, TastyToast.ERROR);
                            gatt.close();
                            mWriteQueue.clear();
                            mFile.delete();
                            FireWareUpdateActivity.this.finish();
                        });
                        break;
                    case UUIDs.CHARACTER_CALLBACK_WRITE:
                        byte[] v = characteristic.getValue();
                        String countString = BlueUtils.bytesToHexString(characteristic.getValue()).substring(0, 4);
                        index = Integer.parseInt(countString.substring(2, 4) + countString.substring(0, 2), 16);
                        mHandler.post(() -> {
                            float c = (float) index / length;
                            mPbFwUpdate.setProgress((int) (c * 100));

//                            BigDecimal b  =   new BigDecimal(c*100);
//                            float   f1   =  b.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
                            mTvUpdateProgress.setText(df.format(c * 100) + "%");
                            LogUtils.d("Progress value = " + c * 100);
                        });
                        LogUtils.d("get  " + index + "  package   All package = " + length);
                        byte[] temp = new byte[buffSize + 2];
                        for (int i = 0; i < buffSize; i++) {
                            temp[i + 2] = mBytes[i + buffSize * index];
                        }
                        //携带第几包信息
                        temp[0] = v[0];
                        temp[1] = v[1];
                        LogUtils.d(BlueUtils.bytesToHexString(temp));
                        callBackNtf.setValue(temp);
                        BleWriteData bleWriteData = new BleWriteData(gatt, callBackNtf, BleWriteData.CHAR_WRITE);
                        mWriteQueue.add(bleWriteData);

                        break;
                    case UUIDs.CHARACTER_FINISH_UPDATE:
                        LogUtils.d(BlueUtils.bytesToHexString(characteristic.getValue()));
                        mHandler.post(() -> {
                            TastyUtils.makeText(R.string.string_update_fail, TastyToast.LENGTH_LONG, TastyToast.ERROR);
                            gatt.close();
                            finish();
//                            ThreadUtils.runOnOtherThread(() -> {
//                                index = 0;
//                                firmWareUpdate();
//                            });
                        });
                        break;
                    default:
                        break;
                }
                isWriting = false;
                nextWrite();
                super.onCharacteristicChanged(gatt, characteristic);
            }

            @Override
            public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                super.onCharacteristicWrite(gatt, characteristic, status);
//                index += 1;
                if (characteristic.getUuid().toString().trim().equalsIgnoreCase(UUIDs.CHARACTER_WRITE_FIRMWARE)) {
                    if (index / length >= 1) {
                        gatt.close();
                        isfinish = true;
                        mHandler.post(() -> {
                            TastyUtils.makeTextShort(R.string.string_update_success, TastyToast.SUCCESS);
                            VCare.get().needUpdate -= 1;
                            if (null != mDevice)
                                DeviceCenter.updateByBtaddress(mDevice.getBtaddress(), VCare.get().getFirmWare().getVersion());
                        });
                        finish();
                    }

                }
                nextWrite();
            }

            @Override
            public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
                if (BluetoothGatt.GATT_SUCCESS == status) {
                    switch (descriptor.getCharacteristic().getUuid().toString().trim()) {
                        case UUIDs.CHARACTER_FINISH_UPDATE:
                            isFinishUpdate = true;
                            break;
                        case UUIDs.CHARACTER_WRITE_FIRMWARE:
                            isNTFWrite = true;
                            break;
                        case UUIDs.CHARACTER_CALLBACK_WRITE:
                            isNTFCallBack = true;
                            break;
                        default:
                            break;
                    }
                }


                if (!isNTFWrite) {
                    enableNotification(true, gatt, writeChar);
                }

                if (!isNTFCallBack) {
                    enableNotification(true, gatt, callBackNtf);
                }

                if (!isFinishUpdate) {
                    enableNotification(true, gatt, finish);
                }

                if (isFinishUpdate && isNTFWrite && isNTFCallBack) {
                    byte[] temp = new byte[buffSize];
                    for (int i = 0; i < buffSize; i++) {
                        temp[i] = mBytes[i];
                    }
                    LogUtils.d(BlueUtils.bytesToHexString(temp));
                    writeChar.setValue(temp);
                    BleWriteData bleWriteData = new BleWriteData(gatt, writeChar, BleWriteData.CHAR_WRITE);
                    mWriteQueue.add(bleWriteData);
                }
                if (mWriteQueue.isEmpty()) {
                    LogUtils.d("1008611" + "==========BLE onDescriptorWrite…写入… 完成");
                    isWriting = false;

                    //可以在此处通知页面或者做其他工作
                } else {
                    LogUtils.d("1008611" + "==========BLEonDescriptorWrite…=========…写下一个");
                    //如果队列中还有数据，继续写入
                    isWriting = false;
                    nextWrite();
                }
                super.onDescriptorWrite(gatt, descriptor, status);
            }
        });
    }

    private void initView() {
        mPbFwUpdate = findViewById(R.id.pb_fw_update);
        mTvUpdateProgress = findViewById(R.id.tv_update_progress);
    }

    @Override
    public void onBackPressed() {
        if (isReset) {
            TastyUtils.makeText(getString(R.string.string_is_updating), TastyToast.LENGTH_LONG, TastyToast.WARNING);
            return;
        }
        if (index != 1 && index != 0) {
            TastyUtils.makeText(getString(R.string.string_is_updating), TastyToast.LENGTH_LONG, TastyToast.WARNING);
            return;
        }
        if (null != mGatt) {
            mGatt.close();
        }
        mHandler.removeCallbacksAndMessages(null);
        super.onBackPressed();
    }

    /**
     * 写入数据，方法是同步的
     */
    private synchronized void nextWrite() {
        LogUtils.d("1008611" + " nextWrite ------ isEmpty()：" + mWriteQueue.isEmpty() + "    isWriting :" + isWriting);
        if (!mWriteQueue.isEmpty() && !isWriting) {
            doWrite(mWriteQueue.poll());//从数据队列里取出数据
        }
    }

    private void doWrite(BleWriteData data) {

        if (data.gatt == null) {
            return;
        }

        isWriting = true;
        latSendData = data;
//        initTimeOutThread();
        switch (data.writeType) {
            case BleWriteData.CHAR_READ:
                data.gatt.readCharacteristic((BluetoothGattCharacteristic) data.object);
                break;
            case BleWriteData.CHAR_WRITE:
                data.gatt.writeCharacteristic((BluetoothGattCharacteristic) data.object);
                break;
            case BleWriteData.DESCRIP_WRITE:
                data.gatt.writeDescriptor((BluetoothGattDescriptor) data.object);
                break;
            default:
                isWriting = false;
                nextWrite();
                break;
        }
        if (index / length >= 1) {
            mHandler.post(() -> {
                TastyUtils.makeTextShort(R.string.string_update_success, TastyToast.SUCCESS);
                VCare.get().needUpdate -= 1;
                DeviceCenter.updateByBtaddress(mDevice.getBtaddress(), VCare.get().getFirmWare().getVersion());
            });
        }
    }

    private void enableNotification(boolean enable, BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
        if (gatt == null || characteristic == null)
            return;

        //这一步必须要有 否则收不到通知
        gatt.setCharacteristicNotification(characteristic, enable);
        BluetoothGattDescriptor clientConfig = characteristic.getDescriptor(UUID.fromString(UUIDs.UUID_NTF_CONFIG));
        if (enable) {
            clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        } else {
            clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
        }
        //准备数据
        BleWriteData bData = new BleWriteData(gatt, clientConfig, BleWriteData.DESCRIP_WRITE);
        //将数据加入队列
        mWriteQueue.add(bData);
    }

    /**
     * 开启超时判断线程
     */
    private void initTimeOutThread() {
        if (timeOutThread == null) {
            timeOutThread_Start = true;
            timeOutThread = new TimeOutThread();
            timeOutThread.start();
        }
    }


    /**
     * 指令超时判断的线程
     */
    class TimeOutThread extends Thread {
        @Override
        public void run() {
            while (timeOutThread_Start) {
                if (isWriting) {
                    if (timeOutTime == 6) {
                        // 超时三秒啦 重发
                        if (timeOutNum == 3) {
                            // 超时3次 放弃当前这条指令 发送下一条
                            isWriting = false;
                            mWriteQueue.clear();
                            mHandler.post(() -> {
                                TastyUtils.makeText(R.string.string_update_fail, TastyToast.LENGTH_LONG, TastyToast.ERROR);
                            });
                            timeOutNum = 0;
                            timeOutTime = 0;
                            //发送超时信息
//                            sendTimeOutMessage();
                            nextWrite();
                            continue;
                        }
                        if (reSendData != null && latSendData != null && reSendData.writeType == latSendData.writeType && Arrays.toString(reSendData.writeData).equals(Arrays.toString(latSendData.writeData))) {
                            timeOutNum++;
                        } else {
                            timeOutNum = 1;
                        }
                        if (latSendData != null) {
                            doWrite(latSendData);
                            reSendData = latSendData;
                        }
                        timeOutTime = 0;
                    } else {
                        int num = 0;
                        while (isWriting) {
                            SystemClock.sleep(10);
                            num++;
                            if (num == 50) {
                                break;
                            }
                        }
                        timeOutTime++;
                    }
                } else {
                    int num = 0;
                    while (!isWriting) {
                        SystemClock.sleep(10);
                        num++;
                        if (num == 1000) {
                            break;
                        }
                    }
                    LogUtils.w("1008611" + "设备指令超时判断的线程 ----Runing--");
                }
            }
        }
    }

}
